using System;
using System.Configuration;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Threading;
using System.Web;
using System.Web.Security;
using System.Web.Configuration;
using System.Text;

namespace BLF.WWW_WWW.Wiki
{

	/// <summary>
	/// Allows access to all the Wiki settings and configuration options.
	/// </summary>
	public static class Settings {

		// Initialization is needed to make locks work in any circumstance
		private static Dictionary<string, string> config;

		/// <summary>
		/// Initializes the internal data.
		/// </summary>
		static Settings() {
			config = new Dictionary<string, string>();
		}

        /// <summary>
        /// Gets the version of the Wiki.
        /// </summary>
        public static string WikiVersion
        {
            get { return "3.0.0"; }
        }

		/// <summary>
		/// Gets the name of the Login Cookie.
		/// </summary>
		public static string LoginCookieName {
			get { return "WikiLogin"; }
		}

		/// <summary>
		/// Gets the name of the Culture Cookie.
		/// </summary>
		public static string CultureCookieName {
			get { return "WikiCulture"; }
		}

		#region Init/Dump

		/// <summary>
		/// Initializes the Configuration data.
		/// </summary>
		public static void Init() {
			lock(config) {
				config = new Dictionary<string, string>();
			}
			FileStream fs = new FileStream(ConfigFile, FileMode.Open, FileAccess.Read, FileShare.None);
			StreamReader sr = new StreamReader(fs, System.Text.Encoding.UTF8);
			string data = sr.ReadToEnd();
			sr.Close();

			data = data.Replace("\r", "");

			string[] lines = data.Split('\n');

			string[] fields;
			for(int i = 0; i < lines.Length; i++) {
				lines[i] = lines[i].Trim();
				
				// Skip comments
				if(lines[i].StartsWith("#")) continue;

				fields = new string[2];
				int idx = lines[i].IndexOf("=");
				if(idx < 0) continue;

				try {
					// Extract key
					fields[0] = lines[i].Substring(0, idx).Trim();
				}
				catch {
					// Unexpected string format
					Log.LogEntry("Config Option '" + lines[i] + "' could not be parsed (key)", EntryType.Error, "SYSTEM");
					continue;
				}

				try {
					// Extract value
					fields[1] = lines[i].Substring(idx + 1).Trim();
				}
				catch {
					// Blank/invalid value?
					Log.LogEntry("Config Option '" + lines[i] + "' could not be parsed (value)", EntryType.Error, "SYSTEM");
					fields[1] = "";
				}

				lock(config) {
					config.Add(fields[0], fields[1]);
				}
			}
			Log.LogEntry("Configuration correctly initialized", EntryType.General, "SYSTEM");
		}

		/// <summary>
		/// Saves the Configuration to disk.
		/// </summary>
		public static void DumpConfig() {
			// Create a backup
			try {
				Tools.WriteFile(Settings.PublicDirectory + Path.GetFileNameWithoutExtension(Settings.ConfigFile) + ".bak" + Path.GetExtension(Settings.ConfigFile), Tools.LoadFile(Settings.ConfigFile));
			}
			catch {
				Log.LogEntry("Unable to create backup file for Config", EntryType.Warning, "SYSTEM");
			}
			FileStream fs = null;
			for(int i = 0; i < Settings.FileAccessTries; i++) {
				try {
					fs = new FileStream(ConfigFile, FileMode.Create, FileAccess.Write, FileShare.None);
					break;
				}
				catch {
					fs = null;
					Thread.Sleep(Settings.FileAccessTryDelay);
				}
			}
			if(fs == null) throw new IOException("Unable to load file " + Settings.ConfigFile);

			StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8);
			
			lock(config) {
				string[] keys = new string[config.Keys.Count];
				config.Keys.CopyTo(keys, 0);
				for(int i = 0; i < keys.Length; i++) {
					sw.Write(keys[i] + " = " + config[keys[i]] + "\r\n");
				}
			}

			sw.Close();
			Log.LogEntry("Config dumped", EntryType.General, "SYSTEM");
		}

		#endregion

		#region HardCoded settings

		/// <summary>
		/// Gets the Master Password, used to encrypt the Users data.
		/// </summary>
		public static string MasterPassword {
			get 
            {
				string pass = WebConfigurationManager.AppSettings["MasterPassword"];
				if(pass == null || pass.Length == 0) throw new Exception("Configuration: MasterPassword cannot be null.");
				return pass;
			}
		}

		/// <summary>
		/// Gets the bytes of the MasterPassword.
		/// </summary>
		public static byte[] MasterPasswordBytes {
			get {
				MD5 md5 = MD5CryptoServiceProvider.Create();
				return md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(MasterPassword));
			}
		}

		/// <summary>
		/// Gets the extension used for Pages.
		/// </summary>
		public static string PageExtension {
			get { return ".htm"; }
		}

		/// <summary>
		/// Gets the Email validation Regex.
		/// </summary>
		public static string EmailRegex {
			get { return @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})$"; }
		}

		/// <summary>
		/// Gets the WikiTitle validation Regex.
		/// </summary>
		public static string WikiTitleRegex {
			get { return ".+"; }
		}

		/// <summary>
		/// Gets the MainUrl validation Regex.
		/// </summary>
		public static string MainUrlRegex {
			get { return @"^https?\://{1}\S+/$"; }
		}

		/// <summary>
		/// Gets the SMTP Server validation Regex.
		/// </summary>
		public static string SmtpServerRegex {
			get { return @"^(?:[a-zA-Z0-9_\-]{1,63}\.?)+(?:[a-zA-Z]{2,})|(?=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})[0-2]*[0-9]*[0-9]+\.[0-2]*[0-9]*[0-9]+\.[0-2]*[0-9]*[0-9]+\.[0-2]*[0-9]*[0-9]+$"; }
		}

		#endregion

		#region Directories and Files

		/// <summary>
		/// Gets a list of Files that can be edited in the Editor.
		/// </summary>
		public static string[] EditableFiles {
			get {
				return new string[] {
					Path.GetFileName(Settings.HeaderFile),
					Path.GetFileName(Settings.SidebarFile),
					Path.GetFileName(Settings.FooterFile),
					Path.GetFileName(Settings.AccountActivationMessageFile),
					Path.GetFileName(Settings.PasswordResetMessageFile),
					Path.GetFileName(Settings.EditNoticeFile),
					Path.GetFileName(Settings.HtmlHeadFile),
					Path.GetFileName(Settings.PageHeaderFile),
					Path.GetFileName(Settings.PageFooterFile)
					};
			}
		}

		/// <summary>
		/// Gets the Root Directory of the Wiki.
		/// </summary>
		public static string RootDirectory {
			get { return System.Web.HttpRuntime.AppDomainAppPath; }
		}

		/// <summary>
		/// Gets the Public Directory of the Wiki.
		/// </summary>
		public static string PublicDirectory {
			get { return RootDirectory + PublicDirectoryName + "\\"; }
		}

		/// <summary>
		/// Gets the Public Directory Name (without the full Path) of the Wiki.
		/// </summary>
		public static string PublicDirectoryName {
			get {
				string dir = WebConfigurationManager.AppSettings["PublicDirectory"];
				dir = dir.Trim('\\', '/'); // Remove '/' and '\' from head and tail
				dir = dir.Replace("/", "\\"); // Replace slashes with backslashes
				if(dir == null || dir.Length == 0) throw new Exception("PublicDirectory cannot be null.");
				else return dir;
			}
		}

		/// <summary>
		/// Gets the Upload Directory.
		/// </summary>
		public static string UploadDirectory {
			get { return PublicDirectory + UploadDirectoryName + "\\"; }
		}

		/// <summary>
		/// Gets the Name of the Upload Directory.
		/// </summary>
		public static string UploadDirectoryName {
			get { return "Upload"; }
		}

		/// <summary>
		/// Gets the Name of the Themes directory.
		/// </summary>
		public static string ThemesDirectoryName {
			get { return "Themes"; }
		}

		/// <summary>
		/// Gets the Themes directory.
		/// </summary>
		public static string ThemesDirectory {
			get { return RootDirectory + ThemesDirectoryName + "\\"; }
		}

		/// <summary>
		/// Gets the Name of the Plugins directory.
		/// </summary>
		public static string PluginsDirectoryName {
			get { return "Plugins"; }
		}

		/// <summary>
		/// Gets the Plugins directory.
		/// </summary>
		public static string PluginsDirectory {
			get { return PublicDirectory + PluginsDirectoryName + "\\"; }
		}

		/// <summary>
		/// Gets the Name of the Plugins' Configuration directory.
		/// </summary>
		public static string PluginsConfigurationDirectoryName {
			get { return "Config"; }
		}

		/// <summary>
		/// Gets the Plugins' Configuration directory.
		/// </summary>
		public static string PluginsConfigurationDirectory {
			get { return PluginsDirectory + PluginsConfigurationDirectoryName + "\\"; }
		}

		/// <summary>
		/// Gets the Plugins' Status file.
		/// </summary>
		public static string PluginsStatusFile {
			get { return PluginsDirectory + "Status.cs"; }
		}

		/// <summary>
		/// Gets the Name of the JavaScript Directory.
		/// </summary>
		public static string JsDirectoryName {
			get { return "JS"; }
		}

		/// <summary>
		/// Gets the JavaScript Directory.
		/// </summary>
		public static string JsDirectory {
			get { return RootDirectory + JsDirectoryName + "\\"; }
		}

		/// <summary>
		/// Gets the Temp Directory.
		/// </summary>
		public static string TempDirectory {
			get { return PublicDirectory + TempDirectoryName + "\\"; }
		}

		/// <summary>
		/// Gets the Name of the Temp Directory.
		/// </summary>
		public static string TempDirectoryName {
			get { return "Temp"; }
		}

		/// <summary>
		/// Gets the Name of the Config File.
		/// </summary>
		public static string ConfigFile {
			get { return PublicDirectory + "Config.cs"; }
		}

		/// <summary>
		/// Gets the Recent Changes file.
		/// </summary>
		public static string RecentChangesFile {
			get { return Settings.PublicDirectory + "RecentChanges.cs"; }
		}

		/// <summary>
		/// Gets the HTML Head file.
		/// </summary>
		public static string HtmlHeadFile {
			get { return PublicDirectory + "HtmlHead.cs"; }
		}

		/// <summary>
		/// Gets the Users file.
		/// </summary>
		public static string UsersFile {
			get { return PublicDirectory + "Users.cs"; }
		}

		/// <summary>
		/// Gets the Pages file.
		/// </summary>
		public static string PagesFile {
			get { return PublicDirectory + "Pages.cs"; }
		}

		/// <summary>
		/// Gets the Categories file.
		/// </summary>
		public static string CategoriesFile {
			get { return PublicDirectory + "Categories.cs"; }
		}

		/// <summary>
		/// Gets the NavigationPaths file.
		/// </summary>
		public static string NavigationPathsFile {
			get { return PublicDirectory + "NavigationPaths.cs"; }
		}

		/// <summary>
		/// Gets the Pages directory.
		/// </summary>
		public static string PagesDirectory {
			get { return PublicDirectory + "Pages\\"; }
		}

		/// <summary>
		/// Gets the Messages Directory.
		/// </summary>
		public static string MessagesDirectory {
			get { return PublicDirectory + "Messages\\"; }
		}

		/// <summary>
		/// Gets the Snippets directory.
		/// </summary>
		public static string SnippetsDirectory {
			get { return PublicDirectory + "Snippets\\"; }
		}

		/// <summary>
		/// Gets the Log file.
		/// </summary>
		public static string LogFile {
			get { return PublicDirectory + "Log.cs"; }
		}

		/// <summary>
		/// Gets the Header file.
		/// </summary>
		public static string HeaderFile {
			get { return PublicDirectory + "Header.cs"; }
		}

		/// <summary>
		/// Gets the Sidebar file.
		/// </summary>
		public static string SidebarFile {
			get { return PublicDirectory + "Sidebar.cs"; }
		}

		/// <summary>
		/// Gets the Footer file.
		/// </summary>
		public static string FooterFile {
			get { return PublicDirectory + "Footer.cs"; }
		}

		/// <summary>
		/// Gets the Page Header File.
		/// </summary>
		public static string PageHeaderFile {
			get { return PublicDirectory + "PageHeader.cs"; }
		}

		/// <summary>
		/// Gets the Page Footer File.
		/// </summary>
		public static string PageFooterFile {
			get { return PublicDirectory + "PageFooter.cs"; }
		}

		/// <summary>
		/// Gets the Edit Notice file.
		/// </summary>
		public static string EditNoticeFile {
			get { return PublicDirectory + "EditNotice.cs"; }
		}

		/// <summary>
		/// Gets the Account Activation Message File.
		/// </summary>
		public static string AccountActivationMessageFile {
			get { return PublicDirectory + "AccountActivationMessage.cs"; }
		}

		/// <summary>
		/// Gets the Password Reset Message File.
		/// </summary>
		public static string PasswordResetMessageFile {
			get { return PublicDirectory + "PasswordResetMessage.cs"; }
		}

		#endregion

		#region Basic Settings and Associated Data

		/// <summary>
		/// Gets or sets the Title of the Wiki.
		/// </summary>
		public static string WikiTitle {
			get {
				string title;
				lock(config) {
					if(config.TryGetValue("WikiTitle", out title)) return title;
					else return "ItalkI Wiki";
				}
			}
			set {
				lock(config) {
					config["WikiTitle"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets the SMTP Server.
		/// </summary>
		public static string SmtpServer {
			get {
				string server;
				lock(config) {
					if(config.TryGetValue("SmtpServer", out server)) return server;
					else return "smtp.server.com";
				}
			}
			set {
				lock(config) {
					config["SmtpServer"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets the SMTP Server Username.
		/// </summary>
		public static string SmtpUsername {
			get {
				string su;
				lock(config) {
					if(config.TryGetValue("SmtpUsername", out su)) return su;
					else return "";
				}
			}
			set {
				lock(config) {
					config["SmtpUsername"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets the SMTP Server Password.
		/// </summary>
		public static string SmtpPassword {
			get {
				string sp;
				lock(config) {
					if(config.TryGetValue("SmtpPassword", out sp)) return sp;
					else return "";
				}
			}
			set {
				lock(config) {
					config["SmtpPassword"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets the SMTP Server Port.
		/// </summary>
		public static int SmtpPort {
			get {
				string sp;
				lock(config) {
					if(config.TryGetValue("SmtpPort", out sp)) return int.Parse(sp);
					else return -1;
				}
			}
			set {
				lock(config) {
					config["SmtpPort"] = value.ToString();
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether to enable SSL in SMTP.
		/// </summary>
		public static bool SmtpSsl {
			get {
				string ss;
				lock(config) {
					if(config.TryGetValue("SmtpSsl", out ss)) return ss.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["SmtpSsl"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether the access to the Wiki is public or not (in this case users won't need to login in order to edit pagesCache).
		/// </summary>
		public static bool PublicAccess {
			get {
				string pa;
				lock(config) {
					if(config.TryGetValue("PublicAccess", out pa)) return pa.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["PublicAccess"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether the access to the Wiki is private or not (in this case users won't be able to view pagesCache unless they are logged in).
		/// </summary>
		public static bool PrivateAccess {
			get {
				string pa;
				lock(config) {
					if(config.TryGetValue("PrivateAccess", out pa)) return pa.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["PrivateAccess"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether, in Public Access mode, anonymous file management is allowed.
		/// </summary>
		public static bool FileManagementInPublicAccessAllowed {
			get {
				string fmpa;
				lock(config) {
					if(config.TryGetValue("FileManagementInPublicAccessAllowed", out fmpa)) return fmpa.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["FileManagementInPublicAccessAllowed"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether Users can create new accounts or not (in this case Register.aspx won't be available).
		/// </summary>
		public static bool UsersCanRegister {
			get {
				string ucr;
				lock(config) {
					if(config.TryGetValue("UsersCanRegister", out ucr)) return ucr.ToLower().Equals("yes");
					else return true;
				}
			}
			set {
				lock(config) {
					config["UsersCanRegister"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether to disable the Captcha control in the Registration Page.
		/// </summary>
		public static bool DisableCaptchaControl {
			get {
				string dc;
				lock(config) {
					if(config.TryGetValue("DisableCaptchaControl", out dc)) return dc.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["DisableCaptchaControl"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets the Account Activation Mode.
		/// </summary>
		public static string AccountActivationMode {
			get {
				string aa;
				lock(config) {
					if(config.TryGetValue("AccountActivationMode", out aa)) return aa;
					else return "EMAIL";
				}
			}
			set {
				string aa = "";
				switch(value.ToLower()) {
					case "email":
						aa = "EMAIL";
						break;
					case "admin":
						aa = "ADMIN";
						break;
					case "auto":
						aa = "AUTO";
						break;
					default:
						throw new ArgumentException("Invalid Account Activation Mode.");
				}
				lock(config) {
					config["AccountActivationMode"] = aa;
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether or not Users can create new Page.
		/// </summary>
		public static bool UsersCanCreateNewPages {
			get {
				string ucc;
				lock(config) {
					if(config.TryGetValue("UsersCanCreateNewPages", out ucc)) return ucc.ToLower().Equals("yes");
					else return true;
				}
			}
			set {
				lock(config) {
					config["UsersCanCreateNewPages"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether or not users can view uploaded Files.
		/// </summary>
		public static bool UsersCanViewFiles {
			get {
				string ucvf;
				lock(config) {
					if(config.TryGetValue("UsersCanViewFiles", out ucvf)) return ucvf.ToLower().Equals("yes");
					else return true;
				}
			}
			set {
				lock(config) {
					config["UsersCanViewFiles"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether or not users can upload Files.
		/// </summary>
		public static bool UsersCanUploadFiles {
			get {
				string ucuf;
				lock(config) {
					if(config.TryGetValue("UsersCanUploadFiles", out ucuf)) return ucuf.ToLower().Equals("yes");
					else return true;
				}
			}
			set {
				lock(config) {
					config["UsersCanUploadFiles"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether or not users can delete Files.
		/// </summary>
		public static bool UsersCanDeleteFiles {
			get {
				string ucdf;
				lock(config) {
					if(config.TryGetValue("UsersCanDeleteFiles", out ucdf)) return ucdf.ToLower().Equals("yes");
					else return true;
				}
			}
			set {
				lock(config) {
					config["UsersCanDeleteFiles"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether or not users can create new Categories.
		/// </summary>
		public static bool UsersCanCreateNewCategories {
			get {
				string ucc;
				lock(config) {
					if(config.TryGetValue("UsersCanCreateNewCategories", out ucc)) return ucc.ToLower().Equals("yes");
					else return true;
				}
			}
			set {
				lock(config) {
					config["UsersCanCreateNewCategories"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether or not users can manage Page Categories.
		/// </summary>
		public static bool UsersCanManagePageCategories {
			get {
				string ucm;
				lock(config) {
					if(config.TryGetValue("UsersCanManagePageCategories", out ucm)) return ucm.ToLower().Equals("yes");
					else return true;
				}
			}
			set {
				lock(config) {
					config["UsersCanManagePageCategories"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets the Default Language.
		/// </summary>
		public static string DefaultLanguage {
			get {
				string l;
				lock(config) {
					if(config.TryGetValue("DefaultLanguage", out l)) return l;
					else return "en-us";
				}
			}
			set {
				lock(config) {
					config["DefaultLanguage"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets the Default Timezone.
		/// </summary>
		public static string DefaultTimezone {
			get {
				string dt;
				lock(config) {
					if(config.TryGetValue("DefaultTimezone", out dt)) return dt;
					else return "0";
				}
			}
			set {
				lock(config) {
					config["DefaultTimezone"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets the DateTime format.
		/// </summary>
		public static string DateTimeFormat {
			get {
				string dtf;
				lock(config) {
					if(config.TryGetValue("DateTimeFormat", out dtf)) return dtf;
					else return "yyyy'/'MM'/'dd' 'HH':'mm";
				}
			}
			set {
				lock(config) {
					config["DateTimeFormat"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets the main URL of the Wiki.
		/// </summary>
		public static string MainUrl {
			get {
				string url;
				lock(config) {
					if(config.TryGetValue("MainUrl", out url)) {
						return url + (!url.EndsWith("/") ? "/" : "");
					}
                    else return "http://www.italki.com/knowledge/";
				}
			}
			set {
				lock(config) {
					config["MainUrl"] = value;
				}
			}
		}

		/// <summary>
		/// Gets the correct path to use with Cookies.
		/// </summary>
		public static string CookiePath {
			get {
				return HttpContext.Current.Request.ApplicationPath;
			}
		}

		/// <summary>
		/// Gets or sets the Contact Email.
		/// </summary>
		public static string ContactEmail {
			get {
				string email;
				lock(config) {
					if(config.TryGetValue("ContactEmail", out email)) return email;
					else return "info@italki.com";
				}
			}
			set {
				lock(config) {
					config["ContactEmail"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets the Sender Email.
		/// </summary>
		public static string SenderEmail {
			get {
				string email;
				lock(config) {
					if(config.TryGetValue("SenderEmail", out email)) return email;
					else return "no-reply@italki.com";
				}
			}
			set {
				lock(config) {
					config["SenderEmail"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets the Defaul Page of the Wiki.
		/// </summary>
		public static string DefaultPage {
			get {
				string page;
				lock(config) {
					if(config.TryGetValue("DefaultPage", out page)) return page;
					else return "default";
				}
			}
			set {
				lock(config) {
					config["DefaultPage"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether to enable double-click Page editing.
		/// </summary>
		public static bool EnableDoubleClickEditing {
			get {
				string dc;
				lock(config) {
					if(config.TryGetValue("EnableDoubleClickEditing", out dc)) return dc.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["EnableDoubleClickEditing"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether to disable the Breadcrumbs Trail.
		/// </summary>
		public static bool DisableBreadcrumbsTrail {
			get {
				string dbc;
				lock(config) {
					if(config.TryGetValue("DisableBreadcrumbsTrail", out dbc)) return dbc.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["DisableBreadcrumbsTrail"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets the # of Backups that are kept. Older backups are deleted after Page editing.
		/// </summary>
		/// <remarks>-1 indicates that no backups are deleted.</remarks>
		public static int KeptBackupNumber {
			get {
				string kb;
				lock(config) {
					if(config.TryGetValue("KeptBackupNumber", out kb)) return int.Parse(kb);
					else return -1;
				}
			}
			set {
				lock(config) {
					config["KeptBackupNumber"] = value.ToString();
				}
			}
		}

		/// <summary>
		/// Gets or sets the Theme.
		/// </summary>
		public static string Theme {
			get {
				string theme;
				lock(config) {
					if(config.TryGetValue("Theme", out theme)) return theme;
					else return "Default";
				}
			}
			set {
				lock(config) {
					config["Theme"] = value;
				}
			}
		}

		/// <summary>
		/// Gets the Theme Path.
		/// </summary>
		public static string ThemePath {
			get {
				return ThemesDirectoryName + "/" + Theme + "/";
			}
		}

		/// <summary>
		/// Gets or sets the list of allowed file types.
		/// </summary>
		public static string[] AllowedFileTypes {
			get {
				string aft;
				lock(config) {
					if(config.TryGetValue("AllowedFileTypes", out aft)) return aft.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
					else return new string[] { "jpg", "jpeg", "gif", "png", "tif", "tiff", "bmp", "htm", "html", "zip", "rar", "pdf", "txt" };
				}
			}
			set {
				string res = "";
				for(int i = 0; i < value.Length; i++) {
					res += value[i];
					if(i != value.Length - 1) res += "|";
				}
				lock(config) {
					config["AllowedFileTypes"] = res;
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether script tags are allowed.
		/// </summary>
		public static bool ScriptTagsAllowed {
			get {
				string sta;
				lock(config) {
					if(config.TryGetValue("ScriptTagsAllowed", out sta)) return sta.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["ScriptTagsAllowed"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets the Logging Level.
		/// </summary>
		public static int LoggingLevel {
			get {
				string ll;
				lock(config) {
					if(config.TryGetValue("LoggingLevel", out ll)) return int.Parse(ll);
					else return 3;
				}
			}
			set {
				lock(config) {
					config["LoggingLevel"] = value.ToString();
				}
			}
		}

		/// <summary>
		/// Gets or sets the Max size of the Log file (KB).
		/// </summary>
		public static int MaxLogSize {
			get {
				string m;
				lock(config) {
					if(config.TryGetValue("MaxLogSize", out m)) return int.Parse(m);
					else return 64;
				}
			}
			set {
				lock(config) {
					config["MaxLogSize"] = value.ToString();
				}
			}
		}

		/// <summary>
		/// Gets or sets a valus specifying whether or not Administrators cannot access the Configuration section in the Administration page.
		/// </summary>
		public static bool ConfigVisibleToAdmins {
			get {
				string cvta;
				lock(config) {
					if(config.TryGetValue("ConfigVisibleToAdmins", out cvta)) return cvta.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["ConfigVisibleToAdmins"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets the Discussion Permissions.
		/// </summary>
		public static string DiscussionPermissions {
			get {
				string dp;
				lock(config) {
					if(config.TryGetValue("DiscussionPermissions", out dp)) return dp;
					else return "PAGE";
				}
			}
			set {
				lock(config) {
					config["DiscussionPermissions"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether or not to disable concurrent editing of Pages.
		/// </summary>
		public static bool DisableConcurrentEditing {
			get {
				string dce;
				lock(config) {
					if(config.TryGetValue("DisableConcurrentEditing", out dce)) return dce.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["DisableConcurrentEditing"] = value ? "YES" : "NO";
				}
			}
		}

		#endregion

		#region Advanced Settings and Associated Data

		

		/// <summary>
		/// Gets or sets the Max file size for upload (in KB).
		/// </summary>
		public static int MaxFileSize {
			get {
				string mfs;
				lock(config) {
					if(config.TryGetValue("MaxFileSize", out mfs)) return int.Parse(mfs);
					else return 10240;
				}
			}
			set {
				lock(config) {
					config["MaxFileSize"] = value.ToString();
				}
			}
		}

		/// <summary>
		/// Gets or sets the # of tries for File Access.
		/// </summary>
		public static int FileAccessTries {
			get {
				string fat;
				lock(config) {
					if(config.TryGetValue("FileAccessTries", out fat)) return int.Parse(fat);
					return 10;
				}
			}
			set {
				lock(config) {
					config["FileAccessTries"] = value.ToString();
				}
			}
		}

		/// <summary>
		/// Gets or sets the delay in milliseconds between File Access tries.
		/// </summary>
		public static int FileAccessTryDelay {
			get {
				string fatd;
				lock(config) {
					if(config.TryGetValue("FileAccessTryDelay", out fatd)) return int.Parse(fatd);
					else return 50;
				}
			}
			set {
				lock(config) {
					config["FileAccessTryDelay"] = value.ToString();
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether to disable the cache.
		/// </summary>
		public static bool DisableCache {
			get {
				string dc;
				lock(config) {
					if(config.TryGetValue("DisableCache", out dc)) return dc.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["DisableCache"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets the Cache Size.
		/// </summary>
		public static int CacheSize {
			get {
				string cs;
				lock(config) {
					if(config.TryGetValue("CacheSize", out cs)) return int.Parse(cs);
					else return 100;
				}
			}
			set {
				lock(config) {
					config["CacheSize"] = value.ToString();
				}
			}
		}

		/// <summary>
		/// Gets or sets the Cache Cut Size.
		/// </summary>
		public static int CacheCutSize {
			get {
				string ccs;
				lock(config) {
					if(config.TryGetValue("CacheCutSize", out ccs)) return int.Parse(ccs);
					else return 20;
				}
			}
			set {
				lock(config) {
					config["CacheCutSize"] = value.ToString();
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether ViewState compression is enabled or not.
		/// </summary>
		public static bool EnableViewStateCompression {
			get {
				string comp;
				lock(config) {
					if(config.TryGetValue("EnableViewStateCompression", out comp)) return comp.ToLower().Equals("yes");
					else return false;
				}
			}
			set {
				lock(config) {
					config["EnableViewStateCompression"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets a value specifying whether HTTP compression is enabled or not.
		/// </summary>
		public static bool EnableHttpCompression {
			get {
				string comp;
				lock(config) {
					if(config.TryGetValue("EnableHttpCompression", out comp)) return comp.ToLower().Equals("yes");
					return false;
				}
			}
			set {
				lock(config) {
					config["EnableHttpCompression"] = value ? "YES" : "NO";
				}
			}
		}

		/// <summary>
		/// Gets or sets the Username validation Regex.
		/// </summary>
		public static string UsernameRegex {
			get {
				string ur;
				lock(config) {
					if(config.TryGetValue("UsernameRegex", out ur)) return ur;
					else return @"^\w[\w\ !$@%^\.\(\)]{3,25}$";
				}
			}
			set {
				lock(config) {
					config["UsernameRegex"] = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets the Password validation Regex.
		/// </summary>
		public static string PasswordRegex {
			get {
				string pr;
				lock(config) {
					if(config.TryGetValue("PasswordRegex", out pr)) return pr;
					else return @"^\w[\w~!@#$%^\(\)\[\]\{\}\.,=\-_\ ]{6,25}$";
				}
			}
			set {
				lock(config) {
					config["PasswordRegex"] = value;
				}
			}
		}

		#endregion

	}

}
